const md5 = require('md5')
let app = getApp();
let config = app.config;

class util {

	constructor() {
		this.tipCloseTimer = null
	}

	checkAuth(callback) {
		let { auth, success, fail } = callback
		if (wx.getSetting && wx.authorize) {
			wx.getSetting({
				success: (res) => {
					res.authSetting[`scope.${auth}`] ? success() : fail()
				},
				fail: () => {
					console.error('check auth failed')
				}
			})
		}
		else {
			fail()
		}
	}

	getAuth(callback) {
		let { auth, success, fail } = callback
		wx.authorize({
			scope: `scope.${auth}`,
			success,
			fail
		})
	}

	config(key, val) {
		if (val && config[key]) {
			return config[key] = val
		}
		return config[key]
	}

	globalData(key, val) {
		try {
			if ((val || this.isString(val) || val === false) && (app.globalData[key] || this.isString(app.globalData[key]) || app.globalData[key] === null)) {
				return app.globalData[key] = val
			}
			if (key.indexOf('Temp') != -1) {
				let temp = app.globalData[key]
				app.globalData[key] = null
				return temp
			}
			return app.globalData[key]
		}
		catch(err) {
			console.error('set/get global data failed')
		}
	}

	showPanelErr(obj) {
		let { p, icon = 'failed', msg = '加载失败', use = '请下拉重试', title = '出错啦' } = obj
		wx.hideNavigationBarLoading()
		wx.stopPullDownRefresh()
		wx.setNavigationBarTitle({
			title,
		})
		p.setData({err:{icon, msg, use}})
	}

	hidePanelErr(p) {
		if(!p.data.err)
			return
		p.setData({err: null})
	}

	showLoadingBox(p) {
		p.setData({ loadingBox: { show: true } })
	}

	hideLoadingBox(p) {
		p.setData({ loadingBox: { show: false } })
	}

	tip(obj) {
		let { p, text, timeout = 3000, done } = obj
		clearTimeout(this.tipCloseTimer)
		p.setData({
			tip: {
				text: false
			}
		})
		p.setData({
			tip: {
				text,
				timeout
			}
		})
		this.tipCloseTimer = setTimeout(() => {
			p.setData({
				tip: {
					text: false
				}
			})
			if (done) {
				done()
			}
		}, timeout)
	}

	success(successMsg = '操作成功', timeout = 1500) {
		wx.showToast({
			title: successMsg,
			icon: 'success',
			duration: timeout,
			mask: true
		})
	}

	error(errTitle = '发生错误', errMsg, callback) {
		wx.showModal({
			title: errTitle,
			content: errMsg,
			showCancel: false,
			success: () => {
				if (callback)
					callback()
			},
			fail: () => {
				if (callback)
					callback()
			}
		})
	}

	modal(title = '系统提示', msg, callback) {
		this.error(title, msg, callback)
	}

	iconBox(icon, title = '系统提示') {
		wx.showToast({
			title: title,
			icon: 'success',
			image: `${icon}.png`
		})
	}

	loading(title) {
		wx.showToast({
			title: title,
			icon: 'loading',
			duration: 60000,
			mask: true
		})
	}

	sign(data = {}) {
		let signStr = ''
		let keys = Object.keys(data)
		keys = keys.sort()
		for (let key of keys) {
			if (!isNaN(key)) {
				continue
			}
			else if (Object.prototype.toString.call(data[key]) == '[object Object]' || Object.prototype.toString.call(data[key]) == '[object Array]') {
				signStr += `&${key}=${JSON.stringify(data[key])}`
			}
			else {
				signStr += `&${key}=${encodeURI(data[key])}`
			}
		}
		signStr += `&token=${this.globalData('token')}`
		signStr = signStr.substring(1)
		console.log('sign str is ' + signStr)
		return this.md5(signStr)
	}

	buildSignUrl(uri = config.requestDomain, data = {}) {
		data.grantType = 'token'
		data.timestamp = this.timestamp()
		data.nonce = this.createRandomStr(10)
		uri += '?'
		for (let key in data) {
			uri += `${key}=${data[key]}&`
		}
		uri += `sign=${this.sign(data)}`
		return config.requestDomain + uri
	}

	request(obj,retryNum) {
		let { method, uri, data, success, fail, sign } = obj
		try {
			if (sign !== false) {
				data.grantType = 'token'
				data.timestamp = this.timestamp()
				data.nonce = this.createRandomStr(10)
				data.sign = this.sign(data)
			}
			wx.request({
				url: config.requestDomain + uri,
				method: method,
				dataType: 'json',
				data: data,
				success: (res) => {
					if (res.data.status == 'success') {
						success(res.data.data)
					}
					else {
						let { code, msg } = res.data
						console.error(code, msg)
						if(code == '-1004' && uri != 'user/checkLogin') {
							this.startLogin({
								success: () => {
									console.log(retryNum)
									if (!retryNum && retryNum != 0)
										retryNum = 0
									else if (retryNum == 2) {
										fail(code, msg)
										return
									}
									console.log(retryNum)
									obj.data.session = this.globalData('session')
									delete obj.data.sign
									this.request(obj, retryNum++)
								},
								fail: () => {
									this.error('登录失败', '登录您的微信用户失败，请稍后重试')
									fail(code, msg)
								}
							})
						}
						else
							fail(code, msg)
					}
				},
				fail: (err) => {
					console.error(err)
					fail('-1', 'request failed')
				}
			})
		}
		catch(err) {
			console.error('create request failed')
			fail('-1', 'create request failed')
		}
	}

	goPage(pageName, data, notBack = false) {
		let uri = ''
		for (let key in data) {
			uri += `&${key}=${data[key]}`
		}
		uri = uri != '' ? ('?' + uri.substr(1, uri.length - 1)) : ''
		if (!notBack) 
			wx.navigateTo({
				url: `../${pageName}/${pageName}${uri}`,
				fail: () => {
					this.error('跳转失败', '悲剧了，跳转到该页面失败，请返回上一层')
				}
			})
		else
			wx.redirectTo({
				url: `../${pageName}/${pageName}${uri}`,
				fail: () => {
					this.error('跳转失败', '悲剧了，跳转到该页面失败，请返回上一层')
				}
			})
	}

	getRange(lat1 = 0, lng1 = 0, lat2 = 0, lng2 = 0, unitConvert = false) {
		const r = 6378137
		let rad1 = lat1 * Math.PI / 180.0
		let rad2 = lat2 * Math.PI / 180.0
		let a = rad1 - rad2
		let b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0
		let range = r * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad1) * Math.cos(rad2) * Math.pow(Math.sin(b / 2), 2)))
		if (unitConvert) {
			if (range < 1000) {
				range = `${parseInt(range)}m`
			}
			else {
				range = `${parseFloat((range / 1000).toFixed(1))}km`
			}
		}
		return range
	}

	timestamp() {
		return parseInt(Date.now() / 1000)
	}

	timestamp2str(timestamp, year = true, month = true, day = true, hours, min, second, split = '-') {
		let date = new Date(timestamp * 1000)
		let _year = `${year ? (date.getFullYear() > 9 ? date.getFullYear() : '0' + date.getFullYear()) + split : ''}`
		let _month = `${month ? (date.getMonth() + 1 > 9 ? date.getMonth() + 1 : '0' + (date.getMonth() + 1)) + split : ''}`
		let _day = `${day ? (date.getDate() > 9 ? date.getDate() : '0' + date.getDate()) : ''} `
		let _hours = `${hours ? (date.getHours() > 9 ? date.getHours() : '0' + date.getHours()) + ':' : ''}`
		let _min = `${min ? (date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()) + ':' : ''}`
		let _second = `${second ? (date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds()) : ''}`
		return `${_year}${_month}${_day}${_hours}${_min}${_second}`
	}

	isString(val) {
		return Object.prototype.toString.call(val) === '[object String]'
	}

	createRandomStr(len) {
		let randomStr = ''
		let material = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
		for (var i = 0; i < len; i++) {
			//添加在素材字符串随机找到的字符
			randomStr += material[parseInt(Math.random() * 61)];
		}
		return randomStr
	}

	md5(str) {
		return md5.hexMD5(str)
	}

	errorHandler(code, msg) {
		const errText = {
			'-1': '无法发送请求，请检查您的网络是否正常',
			'-1000': '非法的请求类型，请稍后重试',
			'-1001': '啊哦，服务器开小差了，请稍后重试',
			'-1003': '啊哦，数据被UFO吸走了，请稍后重试',
			'-1004': '登录状态失效啦，请重新登录本小程序',
			'-1005': '啊哦，服务器处理数据时开小差了，请稍后重试',
			'-1006': '处理数据时失败啦，请稍后重试',
			'-1007': '处理数据时失败啦，请稍后重试',
			'-1008': '处理数据时失败啦，请稍后重试',
			'-1009': '处理数据时失败啦，请稍后重试',
			'-1010': '处理数据时失败啦，请稍后重试',
			'-1011': '登录状态异常，请重新登录本小程序',
			'-1012': '处理数据时失败啦，请稍后重试',
			'-1013': '处理数据时失败啦，请稍后重试',
			'-1014': '处理数据时失败啦，请稍后重试',
			'-1015': '处理数据时失败啦，请稍后重试',
			'-1016': '登录状态失效啦，请重新登录本小程序',
			'-1017': '用户ID不合法，请重新登录本小程序',
			'-1018': '登录状态异常，请重新登录本小程序',
			'-1019': '处理远端数据时失败啦，请稍后重试',
			'-1020': '处理远端数据时失败啦，请稍后重试',
			'-1021': '获取微信权限失败，请稍后重试',
			'-1022': '此应用无权限发起请求，请重新登录本小程序',
			'-1023': '此应用无权限发起请求，请重新登录本小程序',
			'-1024': '处理用户数据时出错啦，请稍后重试',
			'-1025': '哎呀，数据传输时出现了一点差错，请稍后重试',
			'-1026': '哎呀，数据传输时出现了一点差错，请稍后重试',
			'-1027': '哎呀，数据传输时出现了一点差错，请稍后重试',
			'-1028': '哎呀，数据传输时出现了一点差错，请稍后重试',
			'-1029': '绑定的身份不正确，请稍后重试',
			'-1030': '哎呀，数据传输时出现了一点差错，请稍后重试',
			'-1031': '获取微信权限失败，请稍后重试',
			'-1032': '学生只能绑定一次学号哦，如果出现误绑定请向辅导员说明，由辅导员解除绑定再进行重新绑定',
			'-1033': '系统内不存在此学生的数据哦',
			'-1034': '学号不合法，请检查后重试',
			'-1035': '错误的应用ID，请重新登录小程序',
			'-1036': '教师工号不合法，请检查后重试',
			'-1037': '系统内不存在此教师的数据哦',
			'-1038': '重新绑定教师工号需要提供您设置的教师密码哦',
			'-1039': '教师用户密码错误',
			'-1040': '处理数据时失败啦，请稍后重试',
			'-1041': '处理数据时失败啦，请稍后重试',
			'-1042': '处理数据时失败啦，请稍后重试',
			'-1043': '服务器无法处理此请求，请稍后重试',
			'-1044': '处理数据时失败啦，请稍后重试',
			'-1045': '处理学生数据时失败啦，请稍后重试',
			'-1046': '系统内不存在此班级的数据哦',
			'-1047': '系统内不存在此微信用户，请重新登录本小程序'
		}
		return `${code} ${errText[code] || msg}`
	}

	startLogin(callback) {
		this.checkLoginAuth({
			lastCall: callback,
			loginFun: () => {
				let { success, fail } = callback
				if (this.globalData('logined')) {
					wx.stopPullDownRefresh()
					success(this.globalData('userData'))
				}
				if (this.globalData('logining')) {
					wx.stopPullDownRefresh()
					return
				}
				this.loading('登录中')
				this.globalData('logining', true)
				this.checkLogin({
					success: (userData) => {
						wx.hideToast()
						this.globalData('logining', false)
						this.globalData('logined', true)
						success(userData)
					},
					fail: () => {
						console.log('user not login')
						this.login({
							success: (userData) => {
								wx.hideToast()
								this.globalData('logined', true)
								success(userData)
							},
							fail: (code) => {
								wx.hideToast()
								switch (code) {
									case 0:
										console.error('user not auth')
										fail('未获得授权', '您未授权我们获取您的用户信息，您可以点击右上角三个点按钮->关于粿团->再点右上角按钮->设置->开启"用户信息"开关->回到此页面重试')
										console.log(this.globalData('logined'))
										break
									case -1:
										console.error('get user info failed')
										fail('登录失败', '获取用户信息失败啦，请下拉刷新重试哦')
										break
									case -2:
										console.error('user login failed')
										fail('登录失败', '微信登录失败啦，请下拉刷新重试哦')
										break
									case -3:
										console.error('send login request failed')
										fail('登录失败', '用户登录失败啦，请下拉刷新重试哦')
										break
								}

							}
						})
						this.globalData('logining', false)
					}
				})
			}
		})
	}

	checkLoginAuth(callback) {
		let { lastCall, loginFun } = callback
		this.checkAuth({
			auth: 'userInfo',
			success: () => {
				loginFun()
			},
			fail: () => {
				this.getAuth({
					auth: 'userInfo',
					success: () => {
						loginFun()
					},
					fail: () => {
						wx.hideToast()
						wx.showModal({
							title: '未授权',
							content: '粿团需要您授权微信登录才能够正常使用哦(￣▽￣)',
							cancelText: '我拒绝',
							confirmText: '重新授权',
							success: (res) => {
								if (res.confirm) {
									wx.openSetting({
										success: (res) => {
											if (res.authSetting['scope.userInfo'])
												loginFun()
											else
												this.start(lastCall)
										},
										fail: () => {
											this.start(lastCall)
										}
									})
								}
								else {
									wx.navigateBack()
								}
							}
						})
					}
				})
			}
		})
	}

	checkLogin(callback) {
		let { success, fail } = callback
		let session = this.globalData('session')
		let token = this.globalData('token')
		if (!session || !token || token == '' || session == '') {
			fail()
			return
		}
		console.log(`now session is ${session}`)
		wx.checkSession({
			success: () => {
				this.request({
					method: 'get',
					uri: 'user/checkLogin',
					data: {
						session
					},
					success: (userData) => {
						this.globalData('userData', userData)
						this.globalData('logined', true)
						wx.setStorage({
							key: 'userData',
							data: userData
						})
						success(userData)
					},
					fail: (code, msg) => {
						this.globalData('logined', false)
						fail()
					}
				})
			},
			fail
		})
	}

	login(callback) {
		let { success, fail } = callback
		wx.login({
			success: (res) => {
				let { code } = res
				wx.getUserInfo({
					success: (res) => {
						let { encryptedData, iv, userInfo } = res
						this.request({
							method: 'post',
							uri: 'user/login',
							data: {
								loginType: 'wxapp',
								wxCode: code,
								wxEncrypytedData: encryptedData,
								wxIv: iv
							},
							sign: false,
							success: (data) => {
								let { session, token, userData } = data
								this.globalData('session', session)
								this.globalData('token', token)
								this.globalData('userData', userData)
								wx.setStorage({
									key: 'session',
									data: session
								})
								wx.setStorage({
									key: 'token',
									data: token
								})
								wx.setStorage({
									key: 'userData',
									data: userData
								})
								this.globalData('logined', true)
								success(userData)
							},
							fail: (err) => {
								console.error(err)
								this.globalData('logined', false)
								fail(-3)
							}
						})
					},
					fail: (err) => {
						this.globalData('logined', false)
						if (err.errMsg.indexOf('auth deny') != -1) {
							fail(0)
						}
						else {
							fail(-1)
						}
					}
				})
			},
			fail: (err) => {
				console.error(err)
				this.globalData('logined', false)
				fail(-2)
			}
		})
	}

}

module.exports = new util